Tolerate login-shell noise in GitHub CLI JSON output#378
Merged
Conversation
…e failures
A login shell sources .zprofile/.zlogin before gh runs, so banner or version-manager
output prepends to captured stdout and corrupts the JSON. JSONDecoder then throws a
DecodingError that surfaces in the GitHub settings pane as the opaque 'The data couldn't
be read because it isn't in the correct format', even though gh is installed, authed, and
returns valid JSON in the user's terminal.
Enumerate every balanced top-level JSON value ({...} or [...]) in the output, skipping
openers that never balance (a stray brace from a verbose shell), and decode the last
decodable span since gh prints its JSON after any leading noise. Applied at all five gh JSON
decode sites that share the polluted stdout via runGh. A missing payload throws a
shell-pollution message; a present-but-undecodable one throws a version-incompatibility
message (only when the span was valid JSON) and logs the underlying error. latestRun and
resolveRemoteInfo go through decodeIfPresent so a no-payload result stays nil (no runs / no
remote) while leading noise is tolerated and a genuine parse failure is logged. Also fix the
latent multi-host bug where auth-status scanned an arbitrary host: it now prefers github.com,
then a stable sort, so selection is deterministic even when more than one host is active.
Closes #377
…i-host auth Cover the balanced-span scanner (clean object, banner-prefixed object and array, trailing noise, braces and escaped quotes inside strings, two top-level values in order, a stray unbalanced opener that is skipped, pure noise/empty/unterminated yield no spans), the deterministic multi-host active-account selection (non-first host, prefer github.com, sort when github.com absent, no active account), and end-to-end through the live client that banner-polluted stdout still decodes for authStatus, resolveRemoteInfo, defaultBranch, and latestRun; that latestRun skips a stray-brace banner and prefers the real array over a leading empty-array banner; and that a missing payload, bracket-only noise, and an undecodable payload throw their respective GithubCLIError.commandFailed messages.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The GitHub CLI settings pane shows "The data couldn't be read because it isn't in the correct format" even when
ghis installed, authenticated, andgh auth status --json hostsreturns valid JSON in the user's own terminal.Cause
runGhinvokesghthrough a login shell (zsh -l -c '…'). The-lflag sources.zprofile/.zloginwithout the redirect that only suppresses.zshrc, so any login-file output (a fastfetch/neofetch banner, a version-manager init line, a plainecho) prepends to captured stdout.JSONDecoderthen chokes on the leading noise and throws aDecodingError, which was never wrapped and surfaced verbatim. The same polluted stdout flows throughrunGhto five JSON decode sites, so PR badges, default-branch resolution, and remote-info also failed (the last one silently).Fix
{…}or[…]) in the output, skipping openers that never balance (a stray brace from a verbose shell), and decode the last decodable span, sinceghprints its JSON after any leading noise.SupaLogger, length-capped, so the offending output is retrievable from the log stream.latestRun/resolveRemoteInfokeep their nil contract (no runs / no remote) while tolerating leading noise and logging a genuine parse failure.github.com, then a stable sort, so selection is deterministic.Tests
Adds unit coverage for the balanced-span scanner (banner-prefixed object/array, trailing noise, braces and escaped quotes inside strings, two top-level values, a skipped stray opener, pure-noise/empty/unterminated), the deterministic multi-host selection, and end-to-end through the live client that banner-polluted stdout still decodes for
authStatus,resolveRemoteInfo,defaultBranch, andlatestRun, while missing / bracket-only / undecodable payloads throw their respective errors.Closes #377